//
//  DataList.swift
//  we_framework
//
//  Created by zjs on 16/4/7.
//  Copyright © 2016年 zjs. All rights reserved.
//

import Foundation

final public class Section: NSCopying {
    private let lock = NSRecursiveLock()
    
    // thread unsafe
    private var _objects: [AnyObject]?
    
    // thread safe
    public var objects: [AnyObject]?  {
        get {
            return lock.synchronized {
                return _objects
            }
        }
        set {
            lock.synchronized {
                _objects = newValue
            }
            didChangeBlock?()
        }
    }
    
    public init(_ objects:[AnyObject]? = nil) {
        if let objects = objects {
            self.objects = objects
        }
    }
    
    public func addObject(object: AnyObject) {
        if var myObjects = self.objects {
            myObjects.append(object)
            self.objects = myObjects
        } else {
            self.objects = [object]
        }
    }

    
    public func addObjects(objects: [AnyObject]) {
        if var myObjects = self.objects {
            myObjects.appendContentsOf(objects)
            self.objects = myObjects
        } else {
            self.objects = objects
        }
    }
    
    public func insertObject(object: AnyObject, index:Int) {
        if var myObjects = self.objects {
            guard myObjects.count > index else {return}
            myObjects.insert(object, atIndex: index)
            self.objects = myObjects
        } else if (index == 0) {
            self.objects = [object]
        }
    }
    
    public func removeObject(object: AnyObject) {
        if var myObjects = self.objects {
            myObjects.we_removeObject(object)
            self.objects = myObjects
        }
    }

    
    public func removeAllObjects() {
        objects = nil
        didChangeBlock?()
    }
    
    private var _info: Any?
    public var info: Any?  {
        get {
            return lock.synchronized {
                return _info
            }
        }
        set {
            lock.synchronized {
                self._info = newValue
            }
            didChangeBlock?()
        }
    }
    
    public init(objects:[AnyObject]) {
        self.objects = objects
    }
    
    public var count: Int {
        if let objects = self.objects {
            return objects.count
        } else {
            return 0
        }
    }
    
    internal var didChangeBlock: (() -> Void)?
    
    public subscript (index: Int) -> AnyObject? {
        guard let objects = self.objects else {return nil}
        guard objects.count > index else {return nil}
        return objects[index]
    }
    
    @objc public func copyWithZone(zone: NSZone) -> AnyObject {
        let section = Section(self.objects)
        section.info = self.info
        return section
    }
}


public class DataList: NSCopying {
    private let lock = NSRecursiveLock()
    public private(set) var sections = [Section]()
    public var totalCount = 0
    public var count:Int {
        return self.sections.reduce(0, combine: { (lastCount, section) -> Int in
            return lastCount + section.count
        })
    }
    private var _info: Any?
    public var info: Any?  {
        get {
            return lock.synchronized{
                return _info
            }
        }
        set {
            lock.synchronized{
                self._info = newValue
            }
            didChangeBlock?()
        }
    }

    public var didChangeBlock: (() -> Void)?

    private var needsChange = false
    
    public init(_ sections:[Section]? = nil) {
        if let sections = sections {
            self.addSections(sections)
        }
    }
    
    @objc public func copyWithZone(zone: NSZone) -> AnyObject {
        return DataList(self.sections)
    }
    
    public func add(objects:[AnyObject]?, sectionIndex:Int=0) {
        lock.synchronized {
            let diff = sectionIndex + 1 - self.sections.count
            if (diff > 0) {
                diff.times {_ in
                    self.addSection(Section())
                }
            }
            if let objects = objects {
                self.sections[sectionIndex].addObjects(objects)
            }
        }
        self.didChange()
    }
    
    public func addSections(sections:[Section]) {
        lock.synchronized {
            self.sections.appendContentsOf(sections)
            for section in sections {
                section.didChangeBlock = {[weak self] in
                    guard let `self` = self else {return}
                    self.didChange()
                }
            }
        }
        
        self.didChange()
    }

    
    public func addSection(section:Section) {
        lock.synchronized {
            sections.append(section)
            section.didChangeBlock = {[weak self] in
                guard let `self` = self else {return}
                self.didChange()
            }
        }
        self.didChange()
    }
    
    public func removeSection(section:Section) {
        lock.synchronized {
            sections.we_removeObject(section)
            section.didChangeBlock = nil

        }
        didChange()
    }
    
    public func sectionAt(index:Int) -> Section? {
        return lock.synchronized {
            return sections.count > index ? sections[index] : nil
        }
    }
    
    public subscript (index: Int) -> Section? {
        return self.sectionAt(index)
    }
    
    public func objectAt(section:Int = 0, row:Int) -> Any? {
        return lock.synchronized {
            guard sections.count > section else {return nil}
            let section = sections[section]
            guard section.count > row else {return nil}
            return section.objects![row]
        }
    }
    
    public func objectAt(indexPath:NSIndexPath) -> Any? {
        return self.objectAt(indexPath.section, row: indexPath.row)
    }
    
    public func removeAllSections() {
        lock.synchronized {
            sections.removeAll()
        }
        didChange()
    }
    
    private func didChange() {
        lock.synchronized {
            self.needsChange = true
        }

        dispatch_async(dispatch_get_main_queue()) {[weak self] () -> Void in
            guard let `self` = self else {return}
            if (self.needsChange) {
                self.didChangeBlock?()
                self.lock.synchronized {
                    self.needsChange = false
                }
            }
        }

    }
}

